package se.webbzon.boltzmann.editor.component.sequence;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import se.webbzon.boltzmann.editor.component.AbstractComponent;
import se.webbzon.boltzmann.game.sequence.builder.AbstractSequenceRow;
import se.webbzon.boltzmann.game.sequence.builder.SequenceBuilder;

public class RowPanel extends AbstractComponent {
	
	// Auto generated serial version UID
	private static final long serialVersionUID = -2876998019040731464L;

	// The lists of this panel
	private final JList<AbstractSequenceRow> rows;
	
	// A collection of all listener to this panel
	private final Collection<RowListener> listeners;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public RowPanel(SequenceBuilder builder) {
		super("Sequence Rows");
		listeners = new ArrayList<RowListener>();
		setLayout(new BorderLayout());
		
		// Create row list model
		DefaultListModel<AbstractSequenceRow> rowModel = 
				new DefaultListModel<AbstractSequenceRow>();
		for (int i = 0; i < builder.rows(); i++)
			rowModel.addElement(builder.getRow(i));
		
		// Create content of this panel	
		add(new JLabel("Rows"),BorderLayout.NORTH);
		
		rows = new JList<AbstractSequenceRow>(rowModel);
		rows.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		rows.addListSelectionListener(new ListSelectionListenerImpl());
		rows.setModel(rowModel);
		//rows.setCellRenderer(new SequenceRowListCell());
		JScrollPane rowScrollPane = new JScrollPane(rows);
		add(rowScrollPane,BorderLayout.CENTER);

		JPanel rowButtonPanel = new JPanel();
		rowButtonPanel.setLayout(new BorderLayout());
		rowButtonPanel.add(new JButton(new RemoveRowAction()),BorderLayout.WEST);
		add(rowButtonPanel,BorderLayout.SOUTH);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a listener to this row panel. **/
	public boolean addListener(RowListener listener) {
		return listeners.add(listener);
	}
	
	/** Removes a listener from this row panel. **/
	public boolean removeListener(RowListener listener) {
		return listeners.remove(listener);
	}
	
	/** Clears all the listeners in this row panel. **/
	public void clearListener() {
		listeners.clear();
	}
	
	/** Clears the selection in the row panel. **/
	public void clearSelection() {
		rows.clearSelection();
	}
	
	/** Selects the given sequence row in the row panel. **/
	public void selectRow(AbstractSequenceRow row) {
		rows.setSelectedValue(row, true);
	}
	
	/** Selects the sequence row with the given index in the row
	 * panel. **/
	public void selectRow(int index) {
		rows.setSelectedIndex(index);
	}
	
	/** Returns the selected value in the row panel. If no row is
	 * selected then null is returned. **/
	public AbstractSequenceRow getSelectedValue() {
		return rows.getSelectedValue();
	}
	
	/** Returns the index of the selected row in the row panel. If no
	 * row is selected then -1 is returned. **/
	public int getSelectedIndex() {
		return rows.getSelectedIndex();
	}
	
	/** Adds a sequence row to the end of the row panel. **/
	public void addRow(AbstractSequenceRow row) {
		DefaultListModel<AbstractSequenceRow> rowModel = 
				(DefaultListModel<AbstractSequenceRow>) rows.getModel();
		rowModel.addElement(row);
	}
	
	/** Removes the given sequence row from the row panel. **/
	public boolean removeRow(AbstractSequenceRow row) {
		DefaultListModel<AbstractSequenceRow> rowModel = 
				(DefaultListModel<AbstractSequenceRow>) rows.getModel();
		if (rowModel.removeElement(row)) {
			for (RowListener listener : listeners.toArray(new RowListener[0]))
				listener.removeRow(RowPanel.this, row);
			return true;
		} else
			return false;
	}
	
	/** Inserts the given sequence row at the given index in the
	 * row panel. **/
	public void insertRow(AbstractSequenceRow row, int index) {
		DefaultListModel<AbstractSequenceRow> rowModel = 
				(DefaultListModel<AbstractSequenceRow>) rows.getModel();
		rowModel.insertElementAt(row, index);
	}
	
	/** Returns the number of rows in the row panel. **/
	public int rows() {
		return rows.getModel().getSize();
	}
	
	/** Returns the sequence row at the given index in the row panel. **/
	public AbstractSequenceRow getRow(int index) {
		return rows.getModel().getElementAt(index);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	/** A list selection listener used to listen to selection in the row panel. **/
	private class ListSelectionListenerImpl implements ListSelectionListener {

		/*============================================================
		Public Methods
		============================================================*/
		
		@Override public void valueChanged(ListSelectionEvent event) {
			AbstractSequenceRow row = rows.getSelectedValue();
			if (row != null)
				for (RowListener listener : listeners.toArray(new RowListener[0]))
					listener.selectRow(RowPanel.this, row);
		}
		
	}
	
	/** An abstract action used for the remove row button. **/
	private final class RemoveRowAction extends AbstractAction {
		
		// Auto generated serial version UID
		private static final long serialVersionUID = -9034617278333798570L;
		
		/*============================================================
		Constructor
		============================================================*/

		public RemoveRowAction() {
			putValue(AbstractAction.NAME,"Remove");
		}

		/*============================================================
		Public Methods
		============================================================*/
		
		@Override public void actionPerformed(ActionEvent event) {
			AbstractSequenceRow row = rows.getSelectedValue();
			if (row != null) 
				removeRow(row);
		}
		
	}

}
